#include "iic.h"
#include "delay.h"

// IIC初始化函数
void IIC_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructer;

    // 启用SDA时钟，如果是IIC_SCL_GPIOx，则为sda scl使用的同一个gpiox
    IIC_SDA_RCCPeriphClockcmd(IIC_SDA_GPIO_RCC, ENABLE);
    // 设置IIC_SDA_GPIO_Pin和IIC_SCL_GPIO_Pin
    GPIO_InitStructer.GPIO_Pin = IIC_SDA_GPIO_Pin | IIC_SCL_GPIO_Pin;
    // 设置GPIO速度为50MHz
    GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz;
    // 设置GPIO模式为推挽输出
    GPIO_InitStructer.GPIO_Mode = GPIO_Mode_Out_PP;
    // 初始化GPIO
    GPIO_Init(IIC_SDA_GPIOx, &GPIO_InitStructer);
}

// 将SDA设置为输出模式
static void SDA_OUT(void)
{
    GPIO_InitTypeDef GPIO_InitStructer;
    // 设置GPIO_PIN
    GPIO_InitStructer.GPIO_Pin = IIC_SDA_GPIO_Pin;
    // 设置GPIO速度为50MHz
    GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz;
    // 设置GPIO模式为推挽输出
    GPIO_InitStructer.GPIO_Mode = GPIO_Mode_Out_PP;
    // 初始化GPIO
    GPIO_Init(IIC_SDA_GPIOx, &GPIO_InitStructer);
}

// 将SDA设置为输入模式
static void SDA_IN(void)
{
    GPIO_InitTypeDef GPIO_InitStructer;
    // 设置GPIO_PIN
    GPIO_InitStructer.GPIO_Pin = IIC_SDA_GPIO_Pin;
    // 设置GPIO速度为50MHz
    GPIO_InitStructer.GPIO_Speed = GPIO_Speed_50MHz;
    // 设置GPIO模式为上拉输入
    GPIO_InitStructer.GPIO_Mode = GPIO_Mode_IPU;
    // 初始化GPIO
    GPIO_Init(IIC_SDA_GPIOx, &GPIO_InitStructer);
}

// 发送IIC开始信号
void IIC_Start(void)
{
    SDA_OUT(); // 设置SDA为输出
    IIC_SDA = 1;    // 确保SDA为高
    IIC_SCL = 1;    // 拉高SCL
    delay_us(20);    // 短暂延时
	
    IIC_SDA = 0;    // 下降沿，开始信号
    delay_us(20);    // 短暂延时
    IIC_SCL = 0;    // 时钟保持低，以便SDA数据变化有效
}

// 发送IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT(); // 设置SDA为输出
    IIC_SCL = 0;
    IIC_SDA = 0;    // SDA设为低
		delay_us(20);    // 确保时间
    IIC_SCL = 1;    // 拉高SCL
    IIC_SDA = 1;    // SDA设为高，停止信号
    delay_us(20);    // 释放SDA，SDA线变为高电平
}

// 等待IIC应答信号
uint8_t IIC_Wait_Ack(void)
{
    uint16_t tempTime = 0;
    SDA_IN(); // 设置SDA为输入
    IIC_SDA = 1;   // 释放数据线，以便从设备发送ACK
    delay_us(10);
    IIC_SCL = 1;
    delay_us(10);
    // 等待0，如果收到ACK则退出循环
    while (GPIO_ReadInputDataBit(IIC_SDA_GPIOx, IIC_SDA_GPIO_Pin))
    {
        tempTime++;
        if(tempTime > 250)
        {
            IIC_Stop(); // 超时则发送停止信号
            return 1;   // 超时返回1
        }
    }
    IIC_SCL = 0;
    return 0; // 收到ACK返回0
}

// 发送IIC应答信号
void IIC_Ack(void)
{
    IIC_SCL = 0; // 拉低SCL
    SDA_OUT();   // 设置SDA为输出
    IIC_SDA = 0; // 拉低SDA
    delay_us(20); // 短暂延时
    IIC_SCL = 1; // 拉高SCL
    delay_us(20); // 短暂延时
    IIC_SCL = 0; // 拉低SCL
}

// 发送IIC非应答信号
void IIC_NAck(void)
{
    IIC_SCL = 0;// 拉低SCL
    SDA_OUT();   // 设置SDA为输出
    IIC_SDA = 1; // 拉高SDA
    delay_us(20); // 短暂延时
    IIC_SCL = 1; // 拉高SCL
    delay_us(20); // 短暂延时
    IIC_SCL = 0; // 拉低SCL
}

// 发送一个字节的数据
void IIC_Send_Byte(u8 data)
{
		u8 t;
		SDA_OUT();
		IIC_SCL = 0; 	    	//拉低时钟开始数据传输
		for(t = 0; t < 8; t++)
		{
			if((data & 0x80) >> 7)
				IIC_SDA = 1;
			else
				IIC_SDA = 0;
			data <<= 1;
			delay_us(20);
			IIC_SCL = 1;
			delay_us(20);
			IIC_SCL = 0;
			delay_us(20);
		}
		delay_us(20);
}

// 读取一个字节的数据
u8 IIC_Read_Byte(unsigned char ack)
{
		u8 i;
		u16 receive = 0;
		SDA_IN();
		for(i = 0; i < 8; i++ )
		{
			IIC_SCL = 0;
			delay_us(20);
			IIC_SCL = 1;
			receive <<= 1;
			if(GPIO_ReadInputDataBit(IIC_SDA_GPIOx, IIC_SDA_GPIO_Pin))
				receive++;
			delay_us(20);
		}
		if (!ack)
			IIC_NAck();//发送nACK
		else
			IIC_Ack(); //发送ACK
		return receive;
}
